package com.errol.sync.sync.extension;

import com.renjia.supervise.entity.settlement.AbsSettleFile;
import com.renjia.supervise.entity.settlement.AbsSettleGroup;
import com.renjia.supervise.entity.settlement.AbsSettlePayrollRecord;
import com.renjia.supervise.service.log.LogService;
import com.renjia.supervise.service.settlement.abs.AbsSettleFileService;
import com.renjia.supervise.service.settlement.abs.AbsSettleGroupService;
import com.renjia.supervise.service.settlement.abs.AbsSettlePayrollService;
import com.renjia.supervise.service.sync.DataSyncServiceImpl;
import com.renjia.supervise.service.sync.DatabaseSyncService;
import lombok.Getter;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 同步执行 结算 相关表的 service，按组（一组三张表）执行同步
 * 根据调用 sync 系列方法传递的 entityClass，同步全部 四个组、或其中一个组
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2021/08/16
 * @since v
 **/
@Service(value = "settlementSyncService")
public class SettlementSyncServiceImpl extends com.renjia.supervise.service.sync.DataSyncServiceImpl {

    private final Map<Class<?>, SettleFacade> facadeMap;
    private final LogService logService;

    public SettlementSyncServiceImpl(com.renjia.supervise.service.sync.DatabaseSyncService databaseSyncService,
                                     List<AbsSettleGroupService<?>> settleGroupServices,
                                     List<AbsSettleFileService<?, ?>> settleFileServices,
                                     List<AbsSettlePayrollService<?, ?>> settlePayrollServices,
                                     LogService logService) {
        super(databaseSyncService);
        this.logService = logService;
        this.facadeMap = new HashMap<>();
        for (int i = 0; i < settleGroupServices.size(); i++) {
            facadeMap.put(settleGroupServices.get(i).getEntityClass(),
                    new SettleFacade(settleGroupServices.get(i), settleFileServices.get(i), settlePayrollServices.get(i)));
        }
    }

    /**
     * 注意：结算相关四个组，每个组都有三张表，同步一个组需要同时同步三张表
     * 允许 entityClass 为 null，表示同步全部四个组，否则同步指定组，此时 E 必须是 {@link AbsSettleGroup} 的子类
     *
     * @param <E>              必须是 {@link AbsSettleGroup} 的子类
     * @param entityClass      必须是 {@link AbsSettleGroup} 子类的 Class，或者 null
     * @param rangeLeft        日期区间左边界，包含
     * @param rangeRight       日期区间右边界，包含
     * @param updateEditedData true 在增量同步新增数据的同时，额外同步当天更新的数据
     * @return 提示信息，或 null 表示成功
     */
    @Override
    public <E> String syncData(Class<E> entityClass, @Nullable LocalDate rangeLeft, @Nullable LocalDate rangeRight, boolean updateEditedData) {
        // TODO: 21/8/16 组的事务控制
        try {
            String errMsg;
            if (entityClass != null) {
                if (!this.facadeMap.containsKey(entityClass)) {
                    return "entityClass 必须是 AbsSettleGroup 的子类";
                }
                errMsg = this.facadeMap.get(entityClass).getEntityClassList()
                        .stream().map(ec -> super.doSyncWrapper(ec, rangeLeft, rangeRight, updateEditedData))
                        .filter(Objects::nonNull).collect(Collectors.joining(","));
            } else {
                errMsg = this.facadeMap.values()
                        .stream().map(settleFacade ->
                                settleFacade.getEntityClassList().stream().map(ec ->
                                        super.doSyncWrapper(ec, rangeLeft, rangeRight, updateEditedData))
                                        .collect(Collectors.toList()))
                        .collect(Collectors.toList())
                        .stream()
                        .flatMap(Collection::stream)
                        .filter(Objects::nonNull)
                        .collect(Collectors.joining(","));
            }
            return "".equals(errMsg) ? null : errMsg;
        } catch (Exception e) {
            logService.error(e, "结算组同步异常");
            return "结算组同步异常：" + e.getMessage();
        }
    }

    @Getter
    static class SettleFacade {
        private final Class<? extends AbsSettleGroup> settleGroupEntityClass;
        private final Class<? extends AbsSettleFile> settleFileEntityClass;
        private final Class<? extends AbsSettlePayrollRecord> settlePayrollEntityClass;

        public SettleFacade(AbsSettleGroupService<?> settleGroupService, AbsSettleFileService<?, ?> settleFileService, AbsSettlePayrollService<?, ?> settlePayrollService) {
            this.settleGroupEntityClass = settleGroupService.getEntityClass();
            this.settleFileEntityClass = settleFileService.getEntityClass();
            this.settlePayrollEntityClass = settlePayrollService.getEntityClass();
        }

        public List<Class<?>> getEntityClassList() {
            return Arrays.asList(settleGroupEntityClass, settleFileEntityClass, settlePayrollEntityClass);
        }
    }
}
